package com.soos.plugin.ds.spring.boot.aop;

import com.soos.plugin.ds.spring.boot.annotations.DS;
import com.soos.plugin.ds.spring.boot.autoconfigure.DBHolder;
import com.soos.plugin.ds.spring.boot.autoconfigure.DBInfo;
import com.soos.plugin.ds.spring.boot.enums.DBEnum;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author SOOS
 * @desc 数据源切面处理类
 * @date 2022/3/3 23:37
 */

@Aspect
@Component
@Order(-10)
public class DynamicDataSourceAop {

    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicDataSourceAop.class);

    /**
     * @author SOOS
     * @desc 切点方法
     * @date 2022/3/12 12:16
     */
    @Pointcut("@within(com.soos.plugin.ds.spring.boot.annotations.DS) || " +
            "@annotation(com.soos.plugin.ds.spring.boot.annotations.DS)")
    public void ds(){

    }

    @Before("ds()")
    public void beforeDS(JoinPoint joinPoint) {
        // 根据不同的注解添加不同的数据库配置
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        DBInfo dbInfo;
        // 判断方法上的注解，方法上的注解，优先于类上的注解
        if (method.isAnnotationPresent(DS.class)) {
            DS ds = method.getAnnotation(DS.class);
            dbInfo = new DBInfo(ds);
        } else if (method.getDeclaringClass().isAnnotationPresent(DS.class)) {
            // 判断类上的注解
            DS ds = method.getDeclaringClass().getAnnotation(DS.class);
            dbInfo = new DBInfo(ds);
        } else {
            // 默认使用主数据库信息
            dbInfo = new DBInfo(DBEnum.MAIN, 0);
        }
        DBHolder.setDB(dbInfo);
        LOGGER.info("选择数据库：{}", dbInfo);
    }

    @After("ds()")
    public void afterDS(JoinPoint joinPoint) {
        // 清除ThreadLocal中的数据库配置
        DBInfo db = DBHolder.getDB();
        DBHolder.remove();
        LOGGER.info("移除数据库：{}", db);
    }
}
